package cate.game.play.fighter;

import cate.common.table.d.GD;
import cate.common.table.d.GDBuff;
import cate.common.table.d.GDSkill;
import cate.common.table.fight.buff.row.BuffRow;
import cate.common.util.XT;
import cate.game.attr.FightAttr;
import cate.game.play.buff.Buff;
import cate.game.play.buff.BuffEnhanceCfg;
import cate.game.play.buff.BuffHandler;
import cate.game.play.buff.BuffParam;
import cate.game.play.buff.h.护盾BH;
import cate.game.play.config.buff.ExBuffCfg;
import cate.game.play.proce.action.ctx.ActionCtx;
import cate.game.play.proce.result.BuffAddResult;
import cate.game.play.skill.Skill;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

@NoteClass("战斗者身上的buff")
public class FightBuffs {

	@NoteField("战斗者")
	@JsonIgnore
	@Transient
	public transient Fighter owner;

	@NoteField("当前拥有的buff们")
	private List<Buff> list = new ArrayList<>();

	public void init(Fighter owner){
		this.owner = owner;
	}


	public void beforeFight() {
		for (Skill s : this.owner.skill.getAllSkill()) {
			if (XT.isNotBlank(s.cfg.row.buffEnhanceList)) {
				for (String code : s.cfg.row.buffEnhanceList) {
					BuffEnhanceCfg cfg = new BuffEnhanceCfg();
					cfg.parse(code);
					addEnhance(cfg);
				}
			}
		}
	}

	@NoteField("buff强化效果")
	private List<BuffEnhanceCfg> enhanceList = new ArrayList<>();

	private void addEnhance(BuffEnhanceCfg cfg) {
		enhanceList.add(cfg);
	}

	public List<BuffEnhanceCfg> getEnhance(BuffRow buffRow) {
		List<BuffEnhanceCfg> results = new ArrayList<>();
		for (BuffEnhanceCfg cfg : enhanceList) {
			if (cfg.test(buffRow)) {
				results.add(cfg);
			}
		}
		return results;
	}


	@JsonIgnore
	public List<BuffHandler> getHandlers() {
		List<BuffHandler> l = new ArrayList<>();
		for (Buff buff : getValidBuffs()) {
			l.add(buff.handler);
		}
		return l;
	}

	@JsonIgnore
	public List<Buff> getValidBuffs(){
		List<Buff> l = new ArrayList<>();
		for (Buff buff : list) {
			if(buff.valid){
				l.add(buff);
			}
		}
		return l;
	}

	public void forValidBuffs(Consumer<Buff> b){
		getValidBuffs().forEach(b);
	}

	/** 遍历执行所有有效的buff的处理器 */
	public void forHandlers(Consumer<BuffHandler> h) {
		getHandlers().forEach(h);
	}


	public List<Integer> tryAddSome(ActionCtx action, int buffId, int count) {
		return tryAddSome(action, owner, buffId, count);
	}

	/**
	 * 尝试添加多个buff
	 * @param action
	 * @param caster
	 * @param buffId
	 * @param count
	 */
	public List<Integer> tryAddSome(ActionCtx action, Fighter caster, int buffId, int count) {
		return tryAddSome(action, caster, buffId, count, GD.W_10000);
	}

	public List<Integer> tryAddSome(ActionCtx action, Fighter caster, int buffId, int count,int addChance) {
		return tryAddSome(action, caster,caster.attr.total(),owner.attr.total(), buffId, count, addChance,null);
	}

	/**
	 * 尝试添加多个buff
	 * @param action
	 * @param caster
	 * @param buffId
	 * @param count
	 */
	public List<Integer> tryAddSome(ActionCtx action, Fighter caster, FightAttr actorAttr, FightAttr targetAttr, int buffId, int count, int addChance, BuffParam param) {
		List<Integer> addPids = new ArrayList<>();
		while (count-- > 0) {
			int pid = tryAddByTid(action, caster, actorAttr, targetAttr, buffId, addChance, param);
			if (pid > GD.INT_0) {
				addPids.add(pid);
			}
		}
		return addPids;
	}


	/**
	 * 尝试添加buff (自己添加)
	 * @param action
	 * @param buffId
	 */
	public int tryAddByTid(ActionCtx action, int buffId) {
		return tryAddByTid(action, owner, buffId, GD.W_10000);
	}

	/**
	 * 尝试添加buff
	 * @param action
	 * @param caster
	 * @param buffId
	 */
	public int tryAddByTid(ActionCtx action, Fighter caster, int buffId) {
		return tryAddByTid(action,caster,buffId,GD.W_10000);
	}

	/**
	 * 尝试添加buff
	 * @param action
	 * @param caster
	 * @param buffId
	 */
	public int tryAddByTid(ActionCtx action, Fighter caster, int buffId, int addChance) {
		return tryAddByTid(action, caster, buffId, addChance, null);
	}

	public int tryAddByTid(ActionCtx action, Fighter caster, int buffId, BuffParam param) {
		return tryAddByTid(action, caster, buffId, GD.W_10000, param);
	}

	public int tryAddByTid(ActionCtx action, Fighter caster, int buffId, int addChance, BuffParam param) {
		return tryAddByTid(action, caster, caster.attr.total(), owner.attr.total(), buffId, addChance, param);
	}

	/**
	 * 尝试添加buff
	 * @param action
	 * @param caster
	 * @param buffId
	 */
	private int tryAddByTid(ActionCtx action, Fighter caster,FightAttr actorAttr,FightAttr targetAttr, int buffId, int addChance, BuffParam param) {
		Buff buffToAdd = action.getCfg().buff.build(this.owner, caster, buffId, action.getRound().index, param);
		return tryAddBuff(action,actorAttr,targetAttr, buffToAdd, addChance);
	}


	/**
	 * 尝试添加buff
	 * @param action
	 * @param buffToAdd
	 */
	public int tryAddBuff(ActionCtx action, FightAttr actorAttr, FightAttr targetAttr, Buff buffToAdd, int addChance) {
		if (buffToAdd == null) {
			return -1;
		}
		//施法者调整buff
		buffToAdd.caster.skill.getHandlers().forEach(h -> h.adjustCastBuff(action, buffToAdd));
		EcResult r = addBuffCheck(action, actorAttr, targetAttr, buffToAdd, addChance);
		if (r.ok()) {
			return addBuffExe(action, buffToAdd);
		} else {
			if (buffToAdd.isCtrl()) {
				owner.skill.forHandlers(h -> h.onAntiCtrl(action, buffToAdd));
			}
			return -1;
		}
	}

	/**
	 * buff添加检测
	 * @param action
	 * @param buffToAdd
	 * @param addChance
	 * @return
	 */
	private EcResult addBuffCheck(ActionCtx action,FightAttr actorAttr,FightAttr targetAttr, Buff buffToAdd, int addChance) {
		EcResult r = new EcResult();
		if (buffToAdd == null) {
			return r.fail("buff不存在");
		}
		if (!buffToAdd.addable()) {
			return r.fail("死亡无法添加");
		}
		//施法者是否允许添加buff
		for (BuffHandler handler : buffToAdd.caster.buff.getHandlers()) {
			if (!handler.allowAddBuffToTarget(action, this.owner, buffToAdd)) {
				return r.fail("buff免疫添加");
			}
		}
		if (!owner.allowAddBuff(action, buffToAdd)) {
			return r.fail("buff免疫添加");
		}
		addChance += buffToAdd.cfg.getExAddChance();

		//对于控制类buff需要计算控制和抗控属性
		if (buffToAdd.isCtrl()) {
			addChance += actorAttr.ctrl() / GD.W_10000_0;
			if (!buffToAdd.cfg.ignAntiCtrl()) {
				addChance -= targetAttr.ctrlAnti() / GD.W_10000_0;
			}
		}
		if (addChance <= 0 || !XT.chance(addChance)) {
			return r.fail("未随机到概率");
		}

		if (buffToAdd.cfg.row.levelOverride) {
			// 启用了相同原型的情况下，高等级Buff覆盖低等级Buff的规则
			for (Buff buff : this.getValidBuffs()) {
				// 相同原型BUFF
				if (buff.cfg.row.protoId == buffToAdd.cfg.row.protoId) {
					// 如果试图添加的buff的等级比当前相同原型的buff的等级还低，那么本次添加忽略
					if (buffToAdd.cfg.row.level < buff.cfg.row.level) {
						return r.fail("存在高等级buff");
					} else {
						// 如果试图添加的buff的等级比当前相同原型的buff的等级相同或更高，那么高级覆盖低级
						buff.markInvalid(action, GDBuff.InvalidReason.LEVEL_OVERRIDE);
						return r.success();
					}
				}
			}
		} else {
			//超过最大堆叠数量就不添加了
			if (buffToAdd.cfg.getPileMax() > 0 && countBuffByTid(buffToAdd.tid) >= buffToAdd.cfg.getPileMax()) {
				return r.fail("超过最大堆叠数量");
			}
		}
		return r.success();
	}

	/**
	 * 执行添加buff
	 * @param action
	 * @param buff
	 * @return buff的pid
	 */
	private int addBuffExe(ActionCtx action, Buff buff) {
		if (buff == null) {
			return -1;
		}
		action.getPlay().reg(buff);
		this.owner.skill.forHandlers(a -> a.beforeOwnerBuffAdd(action, buff));
		list.add(buff);
		if (buff.cfg.row.notice) {
			action.addResult(new BuffAddResult().buffSet(buff));
		}
		FighterPerformance.recBuffAdd(action, buff.caster, buff.cfg.row.protoId);
		buff.onAdd(action);
		this.owner.skill.forHandlers(a -> a.onOwnerAddBuff(action, buff));
		action.getPlay().teamVS.forAreaFighters(a -> {
			a.skill.forHandlers(h -> h.onOtherAddBuff(action, buff));
		});

		List<ExBuffCfg> exBuffs = buff.cfg.getExBuffs();
		if (XT.isNotBlank(exBuffs)) {
			for (ExBuffCfg cfg : exBuffs) {
				switch (cfg.base) {
					case GDSkill.Base.CASTER:
						buff.caster.buff.tryAddByTid(action, buff.caster, cfg.buff, cfg.chance);
						break;
					case GDSkill.Base.TARGET:
						owner.buff.tryAddByTid(action, owner, cfg.buff, cfg.chance);
						break;
					default:
						break;
				}
			}
		}
		return buff.pid;
	}

	/** 统计该tid的buff的数量 */
	public int countBuffByTid(int buffId) {
		int num = 0;
		for (Buff buff : getValidBuffs()) {
			if (buff.tid == buffId) {
				num++;
			}
		}
		return num;
	}


	/** 统计指定标签的buff的数量 */
	public int countBuffByTag(String tag) {
		int num = 0;
		for (Buff buff : getValidBuffs()) {
			if (buff.cfg.containTag(tag)) {
				num++;
			}
		}
		return num;
	}

	/** 统计指定类型的buff的数量 */
	public int countBuffByEffectType(String effectType) {
		int num = 0;
		for (Buff buff : getValidBuffs()) {
			if (StringUtils.equals(buff.cfg.row.effectType,effectType)) {
				num++;
			}
		}
		return num;
	}

	/**
	 * 统计特定条件的buff的数量
	 */
	public int countBuff(Predicate<Buff> predicate) {
		int num = 0;
		for (Buff buff : getValidBuffs()) {
			if (predicate.test(buff)) {
				num++;
			}
		}
		return num;
	}

	/**
	 * 统计是否拥有指定id的buff
	 */
	public boolean containTid(int tid) {
		for (Buff buff : this.getValidBuffs()) {
			if (buff.tid == tid) {
				return true;
			}
		}
		return false;
	}



	/** 统计是否拥有指定标签的buff*/
	public boolean containTags(List<String> tags) {
		for (Buff buff : this.list) {
			if (buff.valid) {
				if (buff.cfg.containTags(tags)) {
					return true;
				}
			}
		}
		return false;
	}

	/** 统计是否拥有指定标签的buff*/
	public boolean containTags(String... tags) {
		for (Buff buff : this.list) {
			if (buff.valid) {
				for (String tag : tags) {
					if (buff.cfg.containTag(tag)) {
						return true;
					}
				}
			}
		}
		return false;
	}

	/** 是否包含指定类型的buff */
	public boolean containType(String... types) {
		for (Buff buff : getValidBuffs()) {
			for (String type : types) {
				if (StringUtils.equals(type, buff.cfg.row.effectType)) {
					return true;
				}
			}

		}
		return false;
	}

	/** 是否包含指定类型的buff */
	public boolean containType(List<String> types) {
		for (Buff buff : getValidBuffs()) {
			for (String type : types) {
				if (StringUtils.equals(type, buff.cfg.row.effectType)) {
					return true;
				}
			}
		}
		return false;
	}

	public Buff findOne(Predicate<Buff> predicate){
		for (Buff buff : getValidBuffs()) {
			if(predicate.test(buff)){
				return buff;
			}
		}
		return null;
	}

	/** 查找一个指定标签的buff */
	public Buff findOneByTag(String tag){
		for (Buff buff : getValidBuffs()) {
			if (buff.cfg.containTag(tag)) {
				return buff;
			}
		}
		return null;
	}


	/** 查找一个指定类型的buff */
	public Buff findOneByType(String type){
		for (Buff buff : getValidBuffs()) {
			if (StringUtils.equals(buff.cfg.row.effectType, type)) {
				return buff;
			}
		}
		return null;
	}

	/** 查找一个指定tid的buff */
	public Buff findOneByTid(int tid) {
		for (Buff buff : getValidBuffs()) {
			if (buff.tid == tid) {
				return buff;
			}
		}
		return null;
	}

	public Buff findOneByPid(int pid) {
		for (Buff buff : getValidBuffs()) {
			if (buff.pid == pid) {
				return buff;
			}
		}
		return null;
	}

	/**
	 * 拥有负面buff
	 * @return
	 */
	public boolean containBad(){
		for (Buff buff : getValidBuffs()) {
			if (!buff.cfg.row.good) {
				return true;
			}
		}
		return false;
	}


	/**
	 * 删除全部特定tid的buff
	 * @param action
	 * @param tid
	 * @return
	 */
	public int removeBuffByTid(ActionCtx action, int tid) {
		return removeBuffByTid(action,tid,-1);
	}

	/**
	 * 删除特定tid的buff (区别于驱散 不用考虑是否可以被驱散)
	 *
	 * @param action
	 * @param tid
	 * @param limit 删除数量
	 * @return
	 */
	public int removeBuffByTid(ActionCtx action, int tid, int limit) {
		return removeBuff(action, a -> a.tid == tid, limit);
	}


	/**
	 * 删除特定buff (区别于驱散 不用考虑是否可以被驱散)
	 * @param action
	 * @param predicate
	 */
	public int removeBuff(ActionCtx action, Predicate<Buff> predicate) {
		return removeBuff(action,predicate,-1);
	}

	/**
	 * 删除特定buff (区别于驱散 不用考虑是否可以被驱散)
	 * @param action
	 * @param predicate
	 */
	public int removeBuff(ActionCtx action, Predicate<Buff> predicate, int limit) {
		int removeNum = 0;
		for (Buff buff : getValidBuffs()) {
			if (predicate.test(buff)) {
				buff.markInvalid(action, GDBuff.InvalidReason.DELETE);
				removeNum++;
				if (limit > 0 && removeNum >= limit) {
					return removeNum;
				}
			}
		}
		return removeNum;
	}


	/** 真正移除失效的buff PS：与buff的onRemove无关！这是程序层面的删除，不是游戏逻辑层面的删除 */
	public void removeInvalid() {
		this.list.removeIf(buff -> !buff.valid);
	}

	/** 更新当前回合 */
	public void updateCurRoundIndex(ActionCtx action, byte phase) {
		forValidBuffs(b -> b.updateCurRoundIndex(action, phase));
	}

	public List<Buff> tryDispelGood(ActionCtx action) {
		return tryDispelGood(action, -1);
	}

	public List<Buff> tryDispelGood(ActionCtx action, int limit) {
		return tryDispel(action, Buff::isGood, limit);
	}

	public List<Buff> tryDispelBad(ActionCtx action) {
		return tryDispelBad(action, -1);
	}

	public List<Buff> tryDispelBad(ActionCtx action, int limit) {
		return tryDispel(action, b -> !b.isGood(), limit);
	}


	/**
	 * 尝试驱散buff
	 * @param action
	 * @param predicate
	 */
	public List<Buff> tryDispel(ActionCtx action, Predicate<Buff> predicate) {
		return tryDispel(action,predicate,-1);
	}

	/**
	 * 尝试驱散buff
	 * @param action
	 * @param predicate
	 * @param limit 限制数量
	 * @return
	 */
	public List<Buff> tryDispel(ActionCtx action, Predicate<Buff> predicate, int limit) {
		List<Buff> dispelBuffs = new ArrayList<>();
		List<Buff> buffs = getValidBuffs();
		//有限制数量的话 就打乱顺序随机驱散
		if (limit > 0) {
			Collections.shuffle(buffs);
		}
		for (Buff buff : buffs) {
			if (!buff.cfg.dispelAble()) {
				continue;
			}
			if (!owner.status.isAllowDispelGood() && buff.isGood()) {
				continue;
			}
			if (predicate.test(buff)) {
				buff.markInvalid(action, GDBuff.InvalidReason.DISPEL);
				dispelBuffs.add(buff);
			}
			if (limit > 0 && dispelBuffs.size() >= limit) {
				return dispelBuffs;
			}
		}
		return dispelBuffs;
	}

	public void onDead(ActionCtx action, Fighter killer) {
		forHandlers(a -> a.onDead(action, killer));
		deadInvalid(action);
	}

	/**
	 * 死亡驱散buff
	 * @param action
	 */
	private void deadInvalid(ActionCtx action) {
		forValidBuffs(buff -> {
			if (buff.cfg.row.deadInvalid) {
				buff.markInvalid(action, GDBuff.InvalidReason.DEAD);
			}
		});
	}


	/** 因为被控制所以无法行动 */
	public boolean noMoveWithCtrl() {
		for (BuffHandler handler : getHandlers()) {
			if(handler.noMoveWithCtrl()){
				return true;
			}
		}
		return false;
	}

	/**
	 * 允许追加行动
	 * @return
	 */
	public boolean allowAppendMove(Skill skill) {
		if (!skill.param.isIgnCtrlMove()) {
			if (isChaos()) {
				return false;
			}
			//禁用普攻
			boolean noAttack = this.containType(GDBuff.Type.缴械);
			if (skill.cfg.row.type == GDSkill.Type.ATTACK && noAttack) {
				return false;
			}
			//禁用主动
			boolean noActive = this.containType(GDBuff.Type.沉默);
			if (skill.cfg.row.type == GDSkill.Type.ACTIVE && noActive) {
				return false;
			}
		}
		return true;
	}

	/** 处于控制之下 */
	public boolean underCtrl(){
		for (Buff buff : getValidBuffs()) {
			if(buff.isCtrl()){
				return true;
			}
		}
		return false;
	}

	/** 处于混乱之中 */
	@JsonIgnore
	public boolean isChaos(){
		return containType(Arrays.asList(GDBuff.Type.嘲讽,GDBuff.Type.混乱));
	}

	//当前总护盾值
	public long shieldValue() {
		long total = 0;
		for (Buff validBuff : this.getValidBuffs()) {
			if (validBuff.handler instanceof 护盾BH) {
				total += ((护盾BH)validBuff.handler).shieldValue();
			}
		}
		return total;
	}
}
